package com.free.chat.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.solon.service.impl.ServiceImpl;
import com.free.chat.common.constant.SysConstant;
import com.free.chat.common.enums.FriendRelationEnum;
import com.free.chat.dao.UsersDao;
import com.free.chat.entity.ApiResult;
import com.free.chat.entity.model.UserRelation;
import com.free.chat.entity.model.Users;
import com.free.chat.entity.vo.FriendGroupVO;
import com.free.chat.entity.vo.UserVO;
import com.free.chat.exception.ApiException;
import com.free.chat.service.UserRelationService;
import com.free.chat.service.UsersService;
import com.free.chat.utils.ServletUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.solon.annotation.Db;
import org.noear.solon.annotation.Inject;
import org.noear.solon.aspect.annotation.Service;
import org.noear.solon.core.handle.UploadedFile;
import org.noear.solon.data.annotation.Tran;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * (Users)表服务实现类
 *
 * @author makejava
 * @since 2022-10-18 22:18:20
 */
@Service
@Slf4j
public class UsersServiceImpl extends ServiceImpl<UsersDao, Users> implements UsersService {
    @Db
    private UsersDao usersDao;
    @Inject
    private UserRelationService userRelationService;
    @Inject("${file.prefix}")
    private String filePrefix;
    @Inject("${file.location}")
    private String fileLocation;

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public Users queryById(Long id) {
        return this.usersDao.selectById(id);
    }

    /**
     * 新增数据
     *
     * @param users 实例对象
     * @return 实例对象
     */
    @Override
    public Users insert(Users users) {
        this.usersDao.insert(users);
        return users;
    }

    /**
     * 修改数据
     *
     * @param users 实例对象
     * @return 实例对象
     */
    @Override
    public Users update(Users users) {
        this.usersDao.update(users, null);
        return this.queryById(users.getId());
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Long id) {
        return this.usersDao.deleteById(id) > 0;
    }

    @Override
    public ApiResult list(Users users) {
        QueryWrapper<Users> wrapper = new QueryWrapper<>();
        List<Users> list = usersDao.selectList(wrapper);
        return ApiResult.success(list);
    }

    /**
     * 登录接口
     *
     * @param users 用户
     */
    @Override
    public ApiResult login(Users users) {
        if (StrUtil.isEmpty(users.getUsername()) || StrUtil.isEmpty(users.getPassword())) {
            return ApiResult.error("请填写用户名或密码");
        }
        QueryWrapper<Users> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", users.getUsername());
        Users user1 = usersDao.selectOne(queryWrapper);
        if (user1 == null) return ApiResult.error("不存在此用户");
        boolean checkFlag = BCrypt.checkpw(users.getPassword(), user1.getPassword());
        if (!checkFlag) {
            return ApiResult.error("用户名密码不正确");
        }

        try {
            // 拼接图片地址
            user1.setFaceImage(user1.getFaceImage() == null ?
                    null : ServletUtil.originUrl() + user1.getFaceImage());

            // sa-token的api
            StpUtil.login(user1.getId());
            Map<String, Object> data = new LinkedHashMap<>();
            data.put(SysConstant.TOKEN_NAME, StpUtil.getTokenInfo().getTokenValue());
            data.put("users", user1);
            return ApiResult.success(data);
        } catch (Exception e) {
            log.error("【登陆】接口出错: {}", e.getMessage());
            throw new ApiException("登陆异常");
        }
    }

    @Override
    @Tran
    public ApiResult register(Users user) {
        LambdaQueryWrapper<Users> usersQueryWrapper = new LambdaQueryWrapper<>();
        usersQueryWrapper.eq(Users::getUsername, user.getUsername());
        Users users = usersDao.selectOne(usersQueryWrapper);
        if (users != null) return ApiResult.error("用户名已存在");
        user.setPassword(BCrypt.hashpw(user.getPassword(), BCrypt.gensalt()));
        usersDao.insert(user);
        UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
        return ApiResult.success(userVO);
    }

    @Override
    public List<FriendGroupVO> getCurrUserFriends(Long id) {
        QueryWrapper<UserRelation> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", id)
                .eq("relation", FriendRelationEnum.NORMAL.type);
        List<UserRelation> userRelations = userRelationService.list(queryWrapper);
        List<Long> idList = new ArrayList<>();
        userRelations.forEach(e -> idList.add(e.getFriendId()));
        if (CollUtil.isEmpty(idList)) return CollUtil.newArrayList();
        List<Users> usersList = usersDao.selectBatchIds(idList);
        usersList.forEach(e -> e.setFaceImage(e.getFaceImage() == null ?
                null : ServletUtil.originUrl() + e.getFaceImage()));
        Map<String, List<Users>> map = usersList.stream().collect(Collectors.groupingBy(Users::getFirstWord));
        List<FriendGroupVO> list = new ArrayList<>();
        map.forEach((k, v) -> {
            FriendGroupVO friendGroupVO = new FriendGroupVO();
            friendGroupVO.setLetter(k);
            friendGroupVO.setData(v);
            list.add(friendGroupVO);
        });
        return list;
    }

    /**
     * 头像文件上传 /img/2022-11-11\\ae692788-b9ba-44cc-b327-d010cce74a6b.jpeg
     * 存储短路径，方便迁移
     *
     * @param file 头像文件
     * @return 返回半路径
     */
    @Override
    public ApiResult uploadImg(UploadedFile file) {
        String format = sdf.format(new Date());
        File folder = new File(fileLocation + format);
        if (!folder.isDirectory()) {
            if (!folder.mkdirs()) {
                return ApiResult.error("文件夹创建失败");
            }
        }
        String oldName = file.name;
        String newName = UUID.randomUUID() + oldName.substring(oldName.lastIndexOf("."));
        try {
            file.transferTo(new File(folder, newName));
            //以上都是普通代码, 这里的/files/ 对应的就是你在WebMvcConfig设置的地址映射
            return ApiResult.success(filePrefix + format + SysConstant.INTERNET_PATH + newName);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ApiResult.error();
    }
}
